package TangramBase;

import TangramCore.Database;
import TangramCore.Hladina;
import TangramCore.HladinaObrys;
import TangramCore.Obrazec;
import TangramCore.Obrys;
import TangramCore.Skladacka;
import TangramCore.Database.ObrazecFilter;

import java.awt.*;
import java.awt.event.*;
import java.text.ParseException;
import java.util.*;
import javax.swing.*;
import javax.swing.tree.*;

public class DescriptionFrame extends JDialog
		implements ItemListener, DocumentWindow, ActionListener,KeyListener,Database.DatabaseChangeListener {

	static final long serialVersionUID = 24362462L;
	
	private JMenuItem mniThis = null;
    private int iWindow = -1;
    private static Point lastPos = new Point(Integer.MIN_VALUE, Integer.MIN_VALUE);
            
    TangramFrame frmDatabase;
    Database database;
    Database.ObrazecData od;
    int showed = -1;
    boolean confirmed = false, checkedDuplicity = false;
    
    HladinaObrys ho;
    Obrazec obrNahled;
    Skladacka skl;
    
    ActionListener updateDate = new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
            now.setTime(System.currentTimeMillis());
            txtDate.setText(df.format(now));
        }
    };
    
    Vector<String> allKeys, selKeys;

    private static final int ID_DESCRAPPLY=13, ID_DESCROK=14, ID_DESCRCANCEL=15,
        ID_DESCRPREV=17, ID_DESCRNEXT=18, ID_DESCRSIMILAR = 19;
    
    JTextField txtName = new JTextField();
    JTextArea txtDescription = new JTextArea();
    JTextField txtAuthor = new JTextField();
    JTextField txtDate = new JTextField();
    
    //JTextField txtNewKeyword = new JTextField("new_keyword");
    JTree treeKeywords;
    JComboBox cmbDate;

    JList lstAllKeywords = new JList();
    JList lstSelKeywords = new JList();
    JButton cmdAdd = new JButton("New");
    JButton cmdNext = new JButton("Next");
    JButton cmdPrev = new JButton("Previous");
    JButton cmdApply = new JButton("Apply");
    JButton cmdOK = new JButton("OK");
    JButton cmdCancel = new JButton("Cancel");
    JButton cmdSimilar = new JButton("Duplicity check");
    JSlider sldTolerance = new JSlider();    
    String strNazev;
    boolean changed = false, changedNazev = false;
    
    public DescriptionFrame(TangramFrame tf, Database d) {
        setTitle("Figure Description");
        //setLayout(new BorderLayout());
        frmDatabase = tf;
        database = d;
        skl = database.getActSet();
        od = new Database.ObrazecData(skl, skl.getDilky());
        ArrayList<Hladina> a = new ArrayList<Hladina>(1);
        ho = new HladinaObrys(
        		od.d, od.o,
        		TangramFrame.vDilky[TangramFrame.iVzhled],
        		TangramFrame.vObrys[TangramFrame.iVzhled],
        		null, Hladina.CENTER, true,
        		new Rectangle(-5,-5,-90,-90)
        );
        a.add(ho);
        obrNahled = new Obrazec(skl,Color.white,a,null,null,null,null);
        //obrNahled.setBorder(txtName.getBorder());
        obrNahled.setPreferredSize(new Dimension(275,275));
        
        treeKeywords = new JTree(frmDatabase.treeModel);
               
        JPanel pnlWest = new JPanel(new BorderLayout());
        //pnlWest.setBackground(Color.white);
        JPanel pnlObr = new JPanel();
        pnlObr.setLayout(new BorderLayout());
        //pnlObr.setBackground(Color.white);
        pnlObr.setBorder(BorderFactory.createTitledBorder("Figure"));
        pnlObr.add(obrNahled);
        
        pnlWest.add(pnlObr,BorderLayout.NORTH);
        
        JPanel pnlDescr = new JPanel(new BorderLayout());
        //pnlDescr.setLayout(new GridLayout(4,1));//BoxLayout(pnlDescr, BoxLayout.Y_AXIS));
        //pnlDescr.setBackground(Color.white);
        
        JPanel pnlName = new JPanel(new BorderLayout());
        //pnlName.setBackground(Color.white);
        pnlName.setBorder(BorderFactory.createTitledBorder("Name"));
        //txtName.setMaximumSize(new Dimension(200,40));
        pnlName.add(txtName,BorderLayout.CENTER);
        pnlDescr.add(pnlName,BorderLayout.NORTH);
        
        JPanel pnlDescription = new JPanel(new BorderLayout());
        //pnlDescription.setBackground(Color.white);
        pnlDescription.setBorder(BorderFactory.createTitledBorder("Description"));
        txtDescription.setLineWrap(true);
        txtDescription.setWrapStyleWord(true);
        //txtDescription. TODO scrollbar;   
        txtDescription.setBorder(txtName.getBorder());
        pnlDescription.add(txtDescription,BorderLayout.CENTER);
        pnlDescr.add(pnlDescription,BorderLayout.CENTER);
        
        JPanel pnlDescrSouth = new JPanel(new GridLayout(2,1));
        //pnlDescrSouth.setBackground(Color.white);
        
        JPanel pnlAuthor = new JPanel(new BorderLayout());
        //pnlAuthor.setBackground(Color.white);
        pnlAuthor.setBorder(BorderFactory.createTitledBorder("Author"));
        //txtAuthor.setMaximumSize(new Dimension(200,40));
        pnlAuthor.add(txtAuthor,BorderLayout.CENTER);
        pnlDescrSouth.add(pnlAuthor);
        //txtDate = new JFormattedTextField(df);
        JPanel pnlDate = new JPanel(new BorderLayout());
        //pnlDate.setBackground(Color.white);
        pnlDate.setBorder(BorderFactory.createTitledBorder("Date"));
        tmrNow.setInitialDelay(0);
        
        txtDate.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){validateDate(txtDate,cmbDate,false);}});
        txtDate.addFocusListener(new FocusAdapter(){public void focusLost(FocusEvent e){validateDate(txtDate,cmbDate,false);}});
        pnlDate.add(txtDate,BorderLayout.CENTER);
        cmbDate = new JComboBox(cmbItems);
        cmbDate.addItemListener(this);
        //cmbDate.setBackground(Color.white);
        cmbDate.setFont(txtName.getFont());
        pnlDate.add(cmbDate,BorderLayout.EAST);
        pnlDescrSouth.add(pnlDate);
        pnlDescr.add(pnlDescrSouth,BorderLayout.SOUTH);
        pnlWest.add(pnlDescr,BorderLayout.CENTER);
        selKeys = new Vector<String>();
        
        MouseListener mlSel = new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if (e.getButton() == MouseEvent.BUTTON3) {
                    TreePath treePath = treeKeywords.getPathForLocation(e.getPoint().x,e.getPoint().y);
                    if(treePath == null)
                        return;
                    Object obj[] = treePath.getPath();
                    boolean added = false;
                    for(int i=1; i<obj.length; i++){
                        String s = ((DefaultMutableTreeNode) obj[i]).toString();
                        if(!selKeys.contains(s))
                            added = added || selKeys.add(s);
                    }
                    if(added){
                        changed = true;
                        setTitle();
                        Collections.<String>sort(selKeys);
                        lstSelKeywords.setListData(selKeys);
                    }
                }
            }
        };
        treeKeywords.addMouseListener(mlSel);
        treeKeywords.setBorder(txtName.getBorder());
        
        //treeKeywords.setToggleClickCount(1);
        JScrollPane scrAll = new JScrollPane(treeKeywords);//lstAllKeywords);
        scrAll.setBorder(BorderFactory.createTitledBorder("Available keywords"));
        //scrAll.setOpaque(false);
        scrAll.setPreferredSize(new Dimension(200,200));
        lstSelKeywords.setFont(txtName.getFont());
        
        MouseListener mlDesel = new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    int index = lstSelKeywords.locationToIndex(e.getPoint());
                    if(index>-1){
                        selKeys.remove(index);
                        lstSelKeywords.setListData(selKeys);
                        changed = true;
                        setTitle();
                    }
                }
            }
        };
        lstSelKeywords.addMouseListener(mlDesel);
        lstSelKeywords.setBorder(txtName.getBorder());
        JScrollPane scrSel = new JScrollPane(lstSelKeywords);
        scrSel.setBorder(BorderFactory.createTitledBorder("Selected keywords"));
        scrSel.setPreferredSize(new Dimension(150,200));
        
        JPanel pnlSouth = new JPanel(new FlowLayout());
        cmdApply.setActionCommand(String.valueOf(ID_DESCRAPPLY));
        cmdApply.addActionListener(this);
        cmdOK.setActionCommand(String.valueOf(ID_DESCROK));
        cmdOK.addActionListener(this);
        cmdCancel.setActionCommand(String.valueOf(ID_DESCRCANCEL));
        cmdCancel.addActionListener(this);
        cmdSimilar.setActionCommand(String.valueOf(ID_DESCRSIMILAR));
        cmdSimilar.addActionListener(this);
        cmdPrev.setActionCommand(String.valueOf(ID_DESCRPREV));
        cmdPrev.addActionListener(this);
        cmdNext.setActionCommand(String.valueOf(ID_DESCRNEXT));
        cmdNext.addActionListener(this);

        pnlSouth.add(cmdPrev);
        pnlSouth.add(cmdNext);
        pnlSouth.add(cmdApply);
        pnlSouth.add(cmdOK);
        pnlSouth.add(cmdSimilar);
        pnlSouth.add(sldTolerance);
        pnlSouth.add(cmdCancel);
        
        Container pane = getContentPane();
        pane.add(pnlWest,BorderLayout.WEST);
        pane.add(scrAll,BorderLayout.CENTER);
        pane.add(scrSel,BorderLayout.EAST);
        pane.add(pnlSouth,BorderLayout.SOUTH);
        //pack();
        //validate();
        int w = 700, h = 600;
        setSize(w,h);
        setResizable(false);
        if(lastPos.x == Integer.MIN_VALUE)
            TangramFrame.centerOnScreen(this);
        else
            setLocation(lastPos);
        txtName.addKeyListener(this);
        txtDescription.addKeyListener(this);
        txtAuthor.addKeyListener(this);
        txtDate.addKeyListener(this);
        obrNahled.addKeyListener(this);
        obrNahled.grabFocus();
        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        addWindowListener(new java.awt.event.WindowAdapter() {public void windowClosing(WindowEvent e){cmdCancel.doClick();}});
    }

    public boolean hasChanged(){
        return changed;
    }

    public boolean hasChangedNazev(){
        return changedNazev;
    }
    
    public static int getInt(JTextField txt){
        try{
            int val = Integer.parseInt(txt.getText());
            txt.setText(String.valueOf(val));
            return val;
        } catch (NumberFormatException ex){
            return Integer.MIN_VALUE;
        }
    }
    
    public static Date getShortDate(JTextField txt){
        try{
            String val = txt.getText();
            if(val.length()>10)
                val = val.substring(0,10);
            Date ret = df.parse(val + " 00:00:00");
            txt.setText(df.format(ret));
            return ret;
        } catch(ParseException ex){
            return null;
        }
    }
    
    public static Date getLongDate(JTextField txt){
        try{
            Date ret = df.parse(txt.getText());
            txt.setText(df.format(ret));
            return ret;
        } catch(ParseException ex){
            return null;
        }
    }
    
    public static Date validateDate(JTextField txt, JComboBox cmb, boolean retValue){
        Color clrValid = Color.white, clrInvalid = Color.yellow;
        Date ret;
        switch(cmb.getSelectedIndex()){
            case 2:
                ret = getLongDate(txt);
                if (ret == null)
                    txt.setBackground(clrInvalid);
                else
                    txt.setBackground(clrValid);
                break;
            case 0:
                ret = getLongDate(txt);
                if (ret == null)
                    txt.setBackground(clrInvalid);
                else
                    txt.setBackground(clrValid);
                break;
            case 1:
                ret = getShortDate(txt);
                if (ret == null)
                    txt.setBackground(clrInvalid);
                else
                    txt.setBackground(clrValid);
                break;
            default:
                int val = getInt(txt);
                ret = null;
                if(val == Integer.MIN_VALUE)
                    txt.setBackground(clrInvalid);
                else{
                    txt.setBackground(clrValid);
                    if(!retValue)
                        break;
                    Calendar cal = new GregorianCalendar();
                    int field = Calendar.MINUTE;
                    switch (cmb.getSelectedIndex()){
                        case 3: //minutes
                            field = Calendar.MINUTE;
                            break;
                        case 4: //hours
                            field = Calendar.HOUR;
                            break;
                        case 5: //days
                            field = Calendar.DAY_OF_MONTH;
                            break;
                        case 6: //weeks
                            field = Calendar.WEEK_OF_MONTH;
                            break;
                        case 7: //months
                            field = Calendar.MONTH;
                            break;
                        case 8: //years
                            field = Calendar.YEAR;
                            break;
                    }
                    cal.add(field,-val);
                    ret = cal.getTime();
                }
                break;
        }
        return ret;
    }

    public static void addTimerListener(ActionListener al){
        tmrNow.addActionListener(al);
        if(!tmrNow.isRunning())
            tmrNow.start();
    }
    
    public static void removeTimerListener(ActionListener al){
        tmrNow.removeActionListener(al);
        if(tmrNow.getActionListeners().length==0)
            tmrNow.stop();
    }
    
    public static void setComboItem(ItemEvent e, ActionListener updateDate, JTextField txtDate){
        JComboBox cmbDate = (JComboBox)e.getSource();
        if(e.getStateChange()==ItemEvent.DESELECTED && e.getItem().equals("now")){
            removeTimerListener(updateDate);
        } else if(e.getStateChange()==ItemEvent.SELECTED){
            switch(cmbDate.getSelectedIndex()){
                case 2:
                    now.setTime(System.currentTimeMillis());
                    txtDate.setText(df.format(now));
                    addTimerListener(updateDate);
                    break;
                case 0:
                    if (getLongDate(txtDate) == null) {
                        now.setTime(System.currentTimeMillis());
                        txtDate.setText(df.format(now));
                    }
                    break;
                case 1:
                    if (getShortDate(txtDate) == null) {
                        //System.out.println("error");
                        now.setTime(System.currentTimeMillis());
                        txtDate.setText(df.format(now).substring(0, 10) + " 00:00:00");
                    }
                    break;
                default:
                    if(getInt(txtDate) == Integer.MIN_VALUE)
                        txtDate.setText("1");
                    break;
            }
            validateDate(txtDate,cmbDate,false);
        }
        
    }
    public void itemStateChanged(ItemEvent e){
        setComboItem(e,updateDate,txtDate);
        changed = true;
        setTitle();
    }
    
    public boolean apply(){
        changed = false;
        changedNazev = false;
        Date d = validateDate(txtDate,cmbDate,true);
        if(d == null)
            return false;
        String s;
        s = txtName.getText();
        changedNazev = !od.nazev.equals(s);
        changed |= changedNazev;
        od.nazev = s;
        s = txtDescription.getText();
        changed |= !od.popis.equals(s);
        od.popis = s;
        s = txtAuthor.getText();
        changed |= !od.autor.equals(s);
        od.autor = s;
        changed |= !od.datum.equals(d);
        od.datum = d;
        changed |= (od.keywords.size()!=selKeys.size() || !od.keywords.containsAll(selKeys));
        od.keywords = new Vector<String>(selKeys);
        show(showed,od);
        return true;
    }
    
    public void show(int i, Database.ObrazecData odNew){
        this.od = i < 0 ? odNew : database.getObrazecData(i);
        showed = i;
        //changed = false;
        confirmed = false;

        ho.update(od.d, od.o);
        obrNahled.update();
        txtName.setText(strNazev=od.nazev);
        txtDescription.setText(od.popis);
        txtAuthor.setText(od.autor);
        txtDate.setText(df.format(od.datum));
        cmbDate.setSelectedIndex(0);
        selKeys = new Vector<String>(od.keywords);
        lstSelKeywords.setListData(selKeys);
        setTitle();
    }
    
    /*public void changeSkladacka(Skladacka skl){
        this.skl = skl;
        obrNahled.setSkladacka(skl,null,null,null);
        loadKeywords(skl.fKeywords);
    }*/

    public void actionPerformed(ActionEvent e){
        int actionID = Integer.parseInt(e.getActionCommand());
        switch (actionID) {
            case ID_DESCROK:
                if(!apply())
                    break;
                showDocument(false);
                confirmed = true;
                if(showed < 0)
                    break;
                //if(changedNazev)//TODO predelat az se budou zobrazovat i jine veci
                if(changed){
                    changed = false;
                    database.changed(Database.CHANGED_DESCRIPTION, showed, true);
                }
                break;
            case ID_DESCRAPPLY:
                if(!apply())
                    break;;
                confirmed = true; //i pri pridavani obrazcu? tot otazka...
                if(showed < 0)
                    break;
                if(changed){
                    changed = false;
                    database.changed(Database.CHANGED_DESCRIPTION, showed, true);
                }
                break;
            case ID_DESCRCANCEL:
                showDocument(false);
                break;
            case ID_DESCRNEXT:
                showNext();
                break;
            case ID_DESCRPREV:
                showPrev();
                break;
            case ID_DESCRSIMILAR:
                checkDuplicity();
                break;
        }
    }

    public void keyTyped(KeyEvent e){  }
    public void keyReleased(KeyEvent e){  }
    public void keyPressed(KeyEvent e){
        if(!e.isActionKey()){
            changed = true;
            setTitle();
        }
        switch(e.getKeyCode()){
            case KeyEvent.VK_PAGE_DOWN:
                showNext();
                break;
            case KeyEvent.VK_PAGE_UP:
                showPrev();
                break;
            case KeyEvent.VK_INSERT:
                ho.prepniVzhled();
                obrNahled.update();
                break;
        }
    }

    private void showNext(){
        if(showed < 0 || showed > database.getSize()-2)
            return;
        show(showed + 1, null);
    }

    private void showPrev(){
        if(showed < 1)
            return;
        show(showed - 1, null);
    }

    private void setTitle(){
        super.setTitle("Figure Description" + sDash + skl.nazev + sLFigureBracket + od.nazev + (changed ? sChanged : sUpToDate) + sRFigureBracket);
        setMenuItemText();
    }
    
    private void setMenuItemText(){
        if(mniThis != null)
            mniThis.setText(sLNumberBracket + iWindow + /*(changed ? sChanged : sUpToDate) +*/ sRNumberBracket + getTitle());
    }
    
    public void setMenuItem(int i, JMenuItem mni){
        iWindow = i;
        mniThis = mni;
        setMenuItemText();
    }
    
    public void restoreState(){
        toFront();//setExtendedState(lastState);
    }
    
    public boolean showDocument(boolean jak){
        boolean ret = jak ? frmDatabase.windowOpened(this):frmDatabase.windowClosed(this);
        setVisible(jak);
        if(jak)
            toFront();
        else {
            if(checkedDuplicity)
                frmDatabase.zrusFilter();
            lastPos = getLocation();
            dispose();
        }
        return ret;
    }
    public boolean databaseChanged(int what, int i){
        if(showed < 0)
            return true;
        boolean myChange = i < 0 || i == showed;
        if(i < 0)
            showed = database.getIndex(od);
        if(showed < 0)
            return false;
        if(myChange && (what & Database.CHANGED_DESCRIPTION) != 0 || (what & Database.CHANGED_OBRAZEC) != 0)
            show(showed, null);
        setTitle();
        return true;
    }
    private boolean checkDuplicity(){
        Database.ObrazecFilter of = new Database.ObrazecFilter();
        of.filterType = ObrazecFilter.FILTER_NEW;
        of.filterSimilar = 1;
        double tolval = (double)sldTolerance.getValue()/100;
        of.tol = Obrys.TOLERANCE_AREA2 + tolval*(5.0-Obrys.TOLERANCE_AREA2);
        of.oSimilar = od.o;
        frmDatabase.filter(of);
        checkedDuplicity = true;
        return true;
     }
}
